package repository

import (
	"context"
	"errors"
	"log"
	"os"
	"time"

	pb "e-commerce/services/product-service/api/pb"

	"github.com/google/uuid"
	"go.mongodb.org/mongo-driver/bson"
	"go.mongodb.org/mongo-driver/mongo"
	"go.mongodb.org/mongo-driver/mongo/options"
	yaml "gopkg.in/yaml.v3"
)

type mongoConfig struct {
	Mongo MongoConfig `yaml:"mongo"`
}

type MongoConfig struct {
	Host     string `yaml:"host"`
	Database string `yaml:"database"`
	Username string `yaml:"username"`
	Password string `yaml:"password"`
}

func NewMongoRepository(configPath string) *ProductRepository {
	yamlFile, err := os.ReadFile(configPath)
	if err != nil {
		log.Fatalf("yaml文件读取失败: %v", err)
	}
	log.Println("yamlFile:", string(yamlFile))
	var mongoConfig mongoConfig
	err = yaml.Unmarshal(yamlFile, &mongoConfig)
	if err != nil {
		log.Fatalf("yaml文件解析失败: %v", err)
	}
	log.Println("mongoConfig:", mongoConfig)
	clientoptions := options.Client().SetHosts([]string{mongoConfig.Mongo.Host}).SetAuth(options.Credential{
		Username:   mongoConfig.Mongo.Username,
		Password:   mongoConfig.Mongo.Password,
		AuthSource: mongoConfig.Mongo.Database,
	}).SetAppName("product-service").
		SetConnectTimeout(10 * time.Second)
	ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
	defer cancel()
	client, err := mongo.Connect(ctx, clientoptions)
	if err != nil {
		log.Fatalf("mongo客户端创建失败: %v", err)
	}

	collection := client.Database(mongoConfig.Mongo.Database).Collection("myapp")

	return &ProductRepository{
		Collection: collection,
	}

}

type ProductRepository struct {
	Collection *mongo.Collection
}

// 按分类获取商品列表
func (r *ProductRepository) FindByCategory(category string) ([]*pb.Product, error) {
	var products []*pb.Product

	filter := bson.M{}
	if category != "" {
		filter["category"] = category
	}

	//按每页10条，分页查询
	// opts := options.Find().SetLimit(10).SetSkip((page - 1) * 10)
	ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
	defer cancel()
	cursor, err := r.Collection.Find(ctx, filter)
	if err != nil {
		return nil, err
	}
	defer cursor.Close(ctx)

	for cursor.Next(ctx) {
		var product pb.Product
		if err := cursor.Decode(&product); err != nil {
			log.Println("Error decoding product:", err)
			continue
		}
		products = append(products, &product)
	}

	return products, nil
}

func (r *ProductRepository) FindByID(id string) (*pb.Product, error) {
	var product pb.Product
	ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
	defer cancel()
	err := r.Collection.FindOne(ctx, bson.M{"id": id}).Decode(&product)
	if err != nil {
		return nil, err
	}
	return &product, nil
}

func (r *ProductRepository) Create(product *pb.Product) (string, error) {
	ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
	defer cancel()

	if product.Id == "" {
		product.Id = uuid.New().String()
		log.Println("product.Id:", product.Id)
	} else {
		// 检查id是否存在,如果存在则返回错误
		_, err := r.FindByID(product.Id)
		if err == nil {
			return "", errors.New("id already exists")
		}
	}

	result, err := r.Collection.InsertOne(ctx, product)
	if err != nil {
		log.Println("InsertOne error:", err)
		return "", err
	}
	log.Println("InsertOne result:", result.InsertedID)
	return product.Id, nil
}

func (r *ProductRepository) Update(id string, product *pb.Product) error {
	// 检查id是否存在
	_, err := r.FindByID(id)
	if err != nil {
		return err
	}
	ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
	defer cancel()
	_, err = r.Collection.UpdateOne(ctx, bson.M{"id": id}, bson.M{"$set": product})
	if err != nil {
		return err
	}
	return nil
}

func (r *ProductRepository) Delete(id string) error {
	// 检查id是否存在
	_, err := r.FindByID(id)
	if err != nil {
		return err
	}
	ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
	defer cancel()
	// 删除
	_, err = r.Collection.DeleteOne(ctx, bson.M{"id": id})
	if err != nil {
		return err
	}
	return nil
}
